﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using up6.utils;

namespace up6.sql
{
    public class SqlParam
    {
        public byte m_valByte = 0;
        public bool m_valBool = false;
        public int m_valInt16 =0;
        public int m_valInt = 0;
        public long m_valLong=0;
        public double m_valDouble = 0;
        public decimal m_valDecimal = 0;
        public string m_valStr=string.Empty;
        public DateTime m_valTm=DateTime.Now;

        protected string m_type;
        protected DbType m_typeDb = DbType.Int32;
        protected string m_name;
        /// <summary>
        /// sql变量名称前缀
        /// </summary>
        protected string m_namePre="@";
        /// <summary>
        /// =
        /// </summary>
        public string pre = "=";
        /// <summary>
        /// 字段长度
        /// </summary>
        public int length = 0;
        public bool primary = false;//是否主键
        public bool identity = false;//是否自增键
        public DataBaseType m_dbt = ConfigReader.dbType();

        public string Type { get { return this.m_type; }
            set
            {
                this.m_type = value;
            } }
        public DbType DbType { get { return this.m_typeDb; }set { this.m_typeDb = value; } }
        public string Name { get { return this.m_name; }set { this.m_name = value; } }
        /// <summary>
        /// 取值，自动判断类型并返回对应值
        /// </summary>
        public object Value { 
            get 
            {
                if (this.DbType == DbType.String) return this.m_valStr;
                else if (this.DbType == DbType.Byte) return this.m_valByte;
                else if (this.DbType == DbType.Int16) return this.m_valInt16;
                else if (this.DbType == DbType.Int32) return this.m_valInt;
                else if (this.DbType == DbType.Int64) return this.m_valLong;
                else if (this.DbType == DbType.Boolean) return this.m_valBool;
                else if (this.DbType == DbType.Double) return this.m_valDouble;
                else if (this.DbType == DbType.Decimal) return this.m_valDecimal;
                else if (this.DbType == DbType.DateTime) return this.m_valTm;
                else return null;
            }
            set
            {
                if (this.DbType == DbType.String) this.m_valStr = value.ToString();
                else if (this.DbType == DbType.Int16) this.m_valInt16 = Convert.ToInt16(value);
                else if (this.DbType == DbType.Int32) this.m_valInt = Convert.ToInt32(value);
                else if (this.DbType == DbType.Int64) this.m_valLong = Convert.ToInt64(value);
                else if (this.DbType == DbType.Boolean) this.m_valBool = Convert.ToBoolean(value);
                else if (this.DbType == DbType.DateTime) this.m_valTm = Convert.ToDateTime(value);
                else if (this.DbType == DbType.Byte) this.m_valByte = Convert.ToByte(value);
                else if (this.DbType == DbType.Double) this.m_valDouble = Convert.ToDouble(value);
                else if (this.DbType == DbType.Decimal) this.m_valDecimal = Convert.ToDecimal(value);
            } }
        /// <summary>
        /// 转换成CMD命名名称：sql:@a,oracle::a
        /// 包含参数占位符的名称，
        /// https://learn.microsoft.com/zh-cn/dotnet/framework/data/adonet/configuring-parameters-and-parameter-data-types
        /// </summary>
        public string ParamterName { get {
                if (this.m_dbt == DataBaseType.ODBC||
                    this.m_dbt == DataBaseType.Kingbase) return "?";
                return this.m_namePre + this.m_name; } }
        public SqlParam() {
            if (ConfigReader.dbType() == DataBaseType.Oracle)
                this.m_namePre = ":";
        }
        public SqlParam(DataBaseType t)
        {
            if (t == DataBaseType.Oracle)
                this.m_namePre = ":";
        }
        public SqlParam(string name,string v, string pre="=")
        {
            if (ConfigReader.dbType() == DataBaseType.Oracle)
                this.m_namePre = ":";
            this.m_name = name;
            this.m_valStr = v;
            this.m_typeDb = DbType.String;
            this.m_type = "string";
            this.pre = pre;
        }
        public SqlParam(string name, byte v,string pre="=")
        {
            this.m_name = name;
            this.m_valByte = v;
            this.m_typeDb = DbType.Byte;
            this.m_type = "byte";
            this.pre = pre;
        }
        public SqlParam(string name, bool v,string pre="=")
        {
            if (ConfigReader.dbType() == DataBaseType.Oracle)
                this.m_namePre = ":";
            this.m_name = name;
            this.m_valBool = v;
            this.m_typeDb = DbType.Boolean;
            this.m_type = "bool";
            this.pre = pre;
        }
        public SqlParam(string name, int v)
        {
            if (ConfigReader.dbType() == DataBaseType.Oracle)
                this.m_namePre = ":";
            this.m_name = name;
            this.m_valInt = v;
            this.m_typeDb = DbType.Int32;
            this.m_type = "int";
        }
        public SqlParam(string name, long v)
        {
            if (ConfigReader.dbType() == DataBaseType.Oracle)
                this.m_namePre = ":";
            this.m_name = name;
            this.m_valLong = v;
            this.m_typeDb = DbType.Int64;
            this.m_type = "long";
        }
        public SqlParam(string name, double v)
        {
            this.m_name = name;
            this.m_valDouble = v;
            this.m_typeDb = DbType.Double;
            this.m_type = "double";
        }
        public SqlParam(string name, decimal v)
        {
            this.m_name = name;
            this.m_valDecimal = v;
            this.m_typeDb = DbType.Decimal;
            this.m_type = "decimal";
        }
        public SqlParam(string name, DateTime v)
        {
            this.m_name = name;
            this.m_valTm = v;
            this.m_typeDb = DbType.DateTime;
            this.m_type = "time";
        }

        public static string mergeNames(SqlParam[] ps,string tmp="{0}",string separator=",") 
        {
            List<string> names = new List<string>();
            foreach(SqlParam p in ps)
            {
                names.Add(string.Format(tmp, p.Name));
            }
            return string.Join(separator, names.ToArray());
        }

        /// <summary>
        /// 自动创建cmd变量，并赋值
        /// </summary>
        /// <param name="cmd"></param>
        public void bind(DbCommand cmd)
        {
            var p = cmd.CreateParameter();
            p.ParameterName = this.ParamterName;
            p.Direction= ParameterDirection.Input;
            p.DbType = this.DbType;
            p.Size = this.length;
            p.Value = this.Value;
            cmd.Parameters.Add(p);
        }

        /// <summary>
        /// 更新cmd中的变量值
        /// </summary>
        /// <param name="cmd"></param>
        public void update(DbCommand cmd)
        {
            cmd.Parameters[this.ParamterName].Value = this.Value;
        }
    }
}